package org.myrpc.client;

import java.util.List;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.LinkedList;

import org.I0Itec.zkclient.IZkChildListener;
import org.I0Itec.zkclient.ZkClient;
import org.myrpc.rpc.RpcRequest;

public class RpcClientProxy implements InvocationHandler{
	private LinkedList<String> listServer = new LinkedList<String>();
	private int count=0;
	private String address;
	
	public RpcClientProxy(String address) {
		this.address = address;
	}

	public <T> T getProxy(Class<T> clazz) {
		initServer();
		return (T) Proxy.newProxyInstance(clazz.getClassLoader(), new Class<?>[] {clazz}, this);
	}
	
	/*初始化服务器列表*/
	public void initServer() {
		ZkClient client = new ZkClient(address,30000,1000);
		String path = "/myrpc";
		if(!client.exists(path)) {
			throw new RuntimeException("没有对应额服务器提供服务");
		}
		
		//预先清空列表
		listServer.clear();
		
		List<String> children = client.getChildren(path);
		for(String p:children) {
			listServer.add(client.readData(path+"/"+p));
		}
		
		//设置节点监听
		client.subscribeChildChanges(path, new IZkChildListener() {
			
			@Override
			public void handleChildChange(String parentPath, java.util.List<String> currentChilds) throws Exception {
				listServer.clear();
				for(String p:currentChilds) {
					listServer.add(client.readData(path+"/"+p));
				}
			}
		});
	}
	
	public String getService() {//轮询算法实现负载均衡
		int index = count%listServer.size();
		count++;
		return listServer.get(index);
	}
	
	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		//封装请求参数
		RpcRequest request =new RpcRequest();
		request.setClassName(method.getDeclaringClass().getName());
		request.setMethodName(method.getName());
		request.setParamTypes(method.getParameterTypes());
		request.setParams(args);
		
		//发送请求
		RpcClient client =new RpcClient();
		String[] service = getService().split(":");
		return client.start(request, service[0], Integer.valueOf(service[1]));
	}

	public String getAddress() {
		return address;
	}

	public void setAddress(String address) {
		this.address = address;
	}

}
